
#ifndef etl_list_h
#define etl_list_h

#include "etl_base.h"

#include <list>

namespace etl
{

template<class T>
class etl_list : public etl_base<T>
{
 private:
  typedef int (*etl_compare)(T a, T b);

 public:
  etl_list() :
    forward( false ),
    backward( false )
    {
    }

  etl_list( const etl_list& obj )
    {
      copy( obj );
    }

  etl_list& operator = ( const etl_list& obj )
    {
      return copy( obj );
    }

  virtual ~etl_list()
    {
    }

  int append( const T& obj )
    {
      internalList.push_back( obj );

      return 0;
    }

  int append_list( const etl_list& obj )
    {
      internalList.splice( internalList.end(), obj.internalList );

      return 0;
    }

  int sub_list( long index, long count )
    {
      typename std::list<T>::iterator iterBegin = internalList.begin();

      iterBegin += index;

      typename std::list<T>::iterator iterEnd = (iterBegin + count);
      
      std::list<T> subList;

      internalList.splice( subList.begin(), subList, iterBegin, iterEnd );

      return 0;
    }

  int prepend( const T& obj )
    {
      internalList.push_front( obj );
      return 0;
    }

  int push( const T& obj )
    {
      return append( obj );
      return 0;
    }

  int insert_before_iter( const T& obj )
    {
      if( this->iter_valid() )
	{
	  internalList.insert( ii, obj );
	  return 0;
	}

      return -1;
    }

  int insert_after_iter( const T& obj )
    {
      if( this->iter_valid() )
	{
	  typename std::list<T>::iterator t = ii + 1;
	  internalList.insert( t, obj );
	  return 0;
	}
      return -1;
    }

  int insert_sorted( const T& obj, etl_compare sc )
    {
      iter_begin();

      while (iter_valid() && (sc(obj, *iter_data()) > 0))
        iter_next();

      if( iter_valid() )
          return insert_before_iter(obj);
      else return append(obj);

      return -1;
    }

  T* get( long index )
    {
      iter_begin();
      for( long i = 0; i < index; i++ )
	iter_next();

      if( iter_valid() )
	return iter_data();

      return NULL;
    }

  T pop()
    {
      T obj = internalList.front();

      internalList.pop_front();

      return obj;
    }

  bool contains( T& obj )
    {
      iter_begin();
      while( iter_valid() )
	{
	  if( *iter_data() == obj )
	    return true;
	  iter_next();
	}
      return false;
    }

  int remove_all( T& obj )
    {
      internalList.remove( obj );
      return 0;
    }

  int remove_at_iter()
    {
      if( iter_valid() )
	{
	  ii = internalList.erase( ii );
	  return 0;
	}
      return -1;
    }

  int clear()
    {
      ii = internalList.erase( internalList.begin(), internalList.end() );
      return 0;
    }

  int iter_begin()
    {
      forward = true;
      backward = false;
      ii = internalList.begin();
      return 0;
    }

  int iter_end()
    {
      backward = true;
      forward = false;
      rii = internalList.rbegin();
      return 0;
    }

  int iter_next()
    {
      ii++;
      return 0;
    }

  int iter_prev()
    {
      rii++;
      return 0;
    }

  T* iter_data()
    {
      if( forward )
	return &(*ii);
      else if( backward )
	return &(*rii);
      return NULL;
    }

  bool iter_valid()
    {
      if( forward )
	{
	  if( ii != internalList.end() )
	    return true;
	}
      else if( backward )
	{
	  if( rii != internalList.rend() )
	    return true;
	}

      return false;
    }

  bool empty()
    {
      return internalList.empty();
    }

  // Note: This is O(N) on the shitty STL.
  long count_elements()
    {
      return internalList.size();
    }

 private:
  std::list<T> internalList;
  bool forward;
  typename std::list<T>::iterator ii;
  bool backward;
  typename std::list<T>::reverse_iterator rii;

  etl_list& copy( const etl_list& obj )
    {
      internalList = obj.internalList;
      ii = obj.ii;
      return *this;
    }
};

}

#endif
